#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/errno.h>
#include <linux/in.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/ethtool.h>
#include <linux/highmem.h>
#include <linux/proc_fs.h>
#include <linux/ctype.h>
#include <linux/version.h>
#include <linux/spinlock.h>
#include <linux/dma-mapping.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/semaphore.h>
#include <linux/phy.h>
#include <linux/bitops.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/irqreturn.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/of_platform.h>
#include <asm/irq.h>
#include <asm/page.h>
#include <asm/setup.h>
#include <linux/crc32.h>
#include <mach/pmu.h>
#include <linux/gpio.h>
#include <mach/fh_gmac_plat.h>
#include <mach/fh_predefined.h>

static struct fh_gmac_platform_data fh_gmac_data;
static u32 g_external_reset_pin;
static void *va_ephy;
static u32 g_tuning_buf[2] = {0};

struct phy_reg_cfg phy_config_array[] = {
	{
		.id = FH_GMAC_PHY_RTL8201,
		.list = {
			{W_PHY, 0x1f, 0x7},
			{W_PHY, 0x10, 0x1ffa},
			{W_PHY, 0x1f, 0},
			{W_PHY, 0x0d, 0x07},
			{W_PHY, 0x0e, 0x3c},
			{W_PHY, 0x0d, 0x4007},
			{W_PHY, 0x0e, 0x0},
			{0},
		},
		.inf_sup = PHY_INTERFACE_MODE_RMII,
	},
	{
		.id = FH_GMAC_PHY_IP101G,
		.list = {
			{W_PHY, 0x14, 0x10},
			{W_PHY, 0x10, 0x1006},
			{W_PHY, 0x14, 0x10},
			{0},
		},
		.inf_sup = PHY_INTERFACE_MODE_RMII,
	},
	{
		.id = FH_GMAC_PHY_TI83848,
		.list = {
			{M_PHY, 0x11, 0x20, 0x20},
			{0},
		},
		.inf_sup = PHY_INTERFACE_MODE_RMII,
	},
	{
		.id = FH_GMAC_PHY_DUMMY,
		.list = {
			{0},
		},
		.inf_sup = PHY_INTERFACE_MODE_RMII,
	},
	{
		.id = FH_GMAC_PHY_INTERNAL_V2,
		.list = {
			{0},
		},
		.inf_sup = PHY_INTERFACE_MODE_MII,
	},
	{
		.id = FH_GMAC_PHY_RTL8211F,
		.list = {
			{0},
		},
		.inf_sup = PHY_INTERFACE_MODE_RGMII,
		.dll_enable = DLL_SETTING_ENABLE,
		.tx_10_dll_val = 128,
		.rx_10_dll_val = 128,
		.tx_10_polarity = 0,
		.rx_10_polarity = 1,


		.tx_100_dll_val = 128,
		.rx_100_dll_val = 128,
		.tx_100_polarity = 0,
		.rx_100_polarity = 1,


		.tx_1000_dll_val = 56,
		.rx_1000_dll_val = 112,
		.tx_1000_polarity = 0,
		.rx_1000_polarity = 1,

	},
	{
		.id = FH_GMAC_PHY_JL2101,
		.list = {
			{0},
		},
		.inf_sup = PHY_INTERFACE_MODE_RGMII,
	},
	{
		.id = FH_GMAC_PHY_MAE0621,
		.list = {
			{W_PHY, 0x1f, 0x0d92},
			{W_PHY, 0x1f, 0x0d92},
			{W_PHY, 0x02, 0x200a},
			{W_PHY, 0x1f, 0x0},

			{W_PHY, 0x1f, 0x0},
			{W_PHY, 0x0d, 0x7},
			{W_PHY, 0x0e, 0x3c},
			{W_PHY, 0x0d, 0x4007},
			{W_PHY, 0x0e, 0x0},
			{W_PHY, 0x0, 0x9140},
			{W_PHY, 0x1f, 0x0},

			{0},
		},
		.inf_sup = PHY_INTERFACE_MODE_RGMII,
	},
	{0},
};

void fh_external_phy_reset(void)
{
	int ret;
	int reset_pin = g_external_reset_pin;


	/*fh_pmu_set_reg_m(REG_PMU_DLL, 0x8080, 0xffff);*/

	ret = gpio_request(reset_pin, "phyreset-gpio");
	if (ret) {
		pr_err("%s: ERROR: request reset pin : %d failed\n",
		__func__, reset_pin);
		return;
	}

	gpio_direction_output(reset_pin, GPIOF_OUT_INIT_HIGH);
	usleep_range(150000, 200000);
	gpio_direction_output(reset_pin, GPIOF_OUT_INIT_LOW);
	/* actual is 20ms */
	usleep_range(150000, 200000);
	gpio_direction_output(reset_pin, GPIOF_OUT_INIT_HIGH);
	usleep_range(150000, 200000);
	gpio_free(reset_pin);
}

static int phy_inf_set(unsigned int inf)
{
	pr_err("set inf is %x\n", inf);
	if (inf == PHY_INTERFACE_MODE_RMII) {
		/*bit 100 : rmii; bit 000 : mii*/
		fh_pmu_set_reg_m(REG_PMU_GMAC_REG, 4, 7);
	} else if (inf == PHY_INTERFACE_MODE_RGMII) {
		fh_pmu_set_reg_m(REG_PMU_GMAC_REG, 1, 7);
	} else {
		fh_pmu_set_reg_m(REG_PMU_GMAC_REG, 0, 7);
	}

	return 0;
}

static int eth_set_speed(unsigned int speed, void *pri)
{
	struct phy_reg_cfg *reg_cfg = (struct phy_reg_cfg *)pri;

	//must be external phy spd set...
	if (reg_cfg->inf_sup == PHY_INTERFACE_MODE_RGMII) {
		//eth_ref_clk_i [25M]
		fh_pmu_set_reg_m(REG_PMU_CLK_DIV4, 3 << 28, 0xf << 28);
		//rgmii_tx_clk_gate	[ungate]
		fh_pmu_set_reg_m(REG_PMU_CLK_GATE1, 0 << 1, 1 << 1);
		//rgmii_tx_clk_polarity
		//fh_pmu_set_reg_m(REG_PMU_CLK_SEL2, 0 << 23, 1 << 23);
		//rgmii_tx_clk_dll
		//fh_pmu_set_reg_m(REG_PMU_DLL, 0 << 7, 0x3f << 7);
		//eth_clk_sel [0]
		fh_pmu_set_reg_m(REG_PMU_CLK_SEL2, 0 << 15, 1 << 15);
		//rgmii_rmii_sel [1]
		fh_pmu_set_reg_m(REG_PMU_CLK_SEL2, 1 << 16, 1 << 16);
		//rgmii_rx_clk_polarity
		//fh_pmu_set_reg_m(REG_PMU_CLK_SEL2, 0 << 24, 1 << 24);
		//rgmii_rx_clk_dll
		//fh_pmu_set_reg_m(REG_PMU_DLL, 0, 0x3f);
		//rgmii_rx_clk_sel [0]
		fh_pmu_set_reg_m(REG_PMU_CLK_SEL2, 0 << 17, 1 << 17);
	} else {
		//eth_ref_clk_i [50M]
		fh_pmu_set_reg_m(REG_PMU_CLK_DIV4, 1 << 28, 0xf << 28);
		//rgmii_tx_clk_gate	[gate]
		fh_pmu_set_reg_m(REG_PMU_CLK_GATE1, 1 << 1, 1 << 1);
		//eth_clk_sel [1]
		fh_pmu_set_reg_m(REG_PMU_CLK_SEL2, 1 << 15, 1 << 15);
		//rgmii_rmii_sel [0]
		fh_pmu_set_reg_m(REG_PMU_CLK_SEL2, 0 << 16, 1 << 16);
		//rgmii_rx_clk_sel [0]
		fh_pmu_set_reg_m(REG_PMU_CLK_SEL2, 0 << 17, 1 << 17);
	}


	switch (speed) {
	case 1000:
		//mac_sed [125M]
		fh_pmu_set_reg_m(REG_PMU_CLK_SEL2, 2 << 12, 3 << 12);
		break;
	case 100:
		//mac_sed
		fh_pmu_set_reg_m(REG_PMU_CLK_SEL2, 1 << 12, 3 << 12);
		break;
	case 10:
		fh_pmu_set_reg_m(REG_PMU_CLK_SEL2, 0 << 12, 3 << 12);
		break;
	}

	return 0;
}

static int phy_sel_func(unsigned int phy_sel)
{

	if (phy_sel == EXTERNAL_PHY) {
		pr_err("BETA :: phy sel external phy with 25M refclk\n");
		//close internal phy
		fh_pmu_set_reg_m(REG_PMU_EPHY_SEL,
		0 << INSIDE_PHY_ENABLE_BIT_POS,
		1 << INSIDE_PHY_ENABLE_BIT_POS);
		//ephy_clk [gate]
		fh_pmu_set_reg_m(REG_PMU_CLK_GATE1, 1 << 3, 1 << 3);
		//eth_ref_clk_out_g [gate]!!!!
		fh_pmu_set_reg_m(REG_PMU_CLK_GATE1, 1 << 0, 1 << 0);
		//eth_ref_clk_i div to [50M]
		//fh_pmu_set_reg_m(REG_PMU_CLK_DIV4, 1 << 28, 0xf << 28);
		// //eth_ref_clk_i div to [25M]
		fh_pmu_set_reg_m(REG_PMU_CLK_DIV4, 3 << 28, 0xf << 28);
		//eth_rmii_clk_g [ungate]
		fh_pmu_set_reg_m(REG_PMU_CLK_GATE1, 0 << 2, 1 << 2);
		//rmii_clk_mode switch [1]
		fh_pmu_set_reg_m(REG_PMU_CLK_SEL2, 1 << 14, 1 << 14);
		//mac speed set [50M]
		fh_pmu_set_reg_m(REG_PMU_CLK_SEL2, 1 << 12, 3 << 12);
		//eth_clk_sel [1]
		fh_pmu_set_reg_m(REG_PMU_CLK_SEL2, 1 << 15, 1 << 15);
		//rgmii_rmii_sel [0]
		fh_pmu_set_reg_m(REG_PMU_CLK_SEL2, 0 << 16, 1 << 16);
		//rgmii_rx_clk_sel [0]
		fh_pmu_set_reg_m(REG_PMU_CLK_SEL2, 0 << 17, 1 << 17);
		//eth_ref_clk_out_g [ungate]!!!!
		fh_pmu_set_reg_m(REG_PMU_CLK_GATE1, 0 << 0, 1 << 0);

	} else {
		pr_err("BETA :: phy sel internal phy\n");
		/*open internal phy*/
		fh_pmu_set_reg_m(REG_PMU_EPHY_SEL,
		1 << INSIDE_PHY_ENABLE_BIT_POS,
		1 << INSIDE_PHY_ENABLE_BIT_POS);
		//ephy_clk  [gate]
		fh_pmu_set_reg_m(REG_PMU_CLK_GATE1, 1 << 3, 1 << 3);
		//eth_ref_clk_out_g [gate]!!!!
		fh_pmu_set_reg_m(REG_PMU_CLK_GATE1, 1 << 0, 1 << 0);
		//eth_rmii_clk_g [gate]
		fh_pmu_set_reg_m(REG_PMU_CLK_GATE1, 1 << 2, 1 << 2);
		//eth_clk_sel				[0]
		fh_pmu_set_reg_m(REG_PMU_CLK_SEL2, 0 << 15, 1 << 15);
		//rgmii_rmii_sel			[0]
		fh_pmu_set_reg_m(REG_PMU_CLK_SEL2, 0 << 16, 1 << 16);
		//rgmii_rx_clk_sel [0]
		fh_pmu_set_reg_m(REG_PMU_CLK_SEL2, 0 << 17, 1 << 17);
		//ephy_clk [ungate]
		fh_pmu_set_reg_m(REG_PMU_CLK_GATE1, 0 << 3, 1 << 3);
		//eth_ref_clk_out_g [ungate]!!!!
		fh_pmu_set_reg_m(REG_PMU_CLK_GATE1, 0 << 0, 1 << 0);
	}

	return 0;	
}



void fh_qos_set_phy_dll_val(u32 tx_val, u32 rx_val)
{
	/*pr_err("set dll tx : rx = %d : %d\n",tx_val, rx_val);*/
	fh_pmu_set_reg_m(REG_PMU_DLL,
	tx_val << 8 | rx_val, 0xffff);
}


void fh_qos_set_phy_polarity(u32 tx_pol, u32 rx_pol)
{
	/*pr_err("set polarity tx : rx = %d : %d\n",tx_pol, rx_pol);*/
	fh_pmu_set_reg_m(REG_PMU_CLK_SEL2,
	tx_pol << 23 | rx_pol << 24, 0x3 << 23);
}


void dump_pol_dll_info(struct soc_reg_tuning *p_tuning)
{
	unsigned int id = 0;

	id = p_tuning->id_l | p_tuning->id_m << 8 | p_tuning->id_h << 16;
	pr_err("%s : %s\n", __FILE__, __func__);
	pr_err("---ID [%x]---\n", id);
	pr_err("---[1000M]---\n");

	pr_err("\tTX_POL :: %s\n",
	((p_tuning->area_pol >> 3) & 1) == DLL_POL_FWD ? "FWD" : "REV");
	pr_err("\tRX_POL :: %s\n",
	((p_tuning->area_pol >> 2) & 1) == DLL_POL_FWD ? "FWD" : "REV");
	pr_err("\tTX_DLL :: 0x%x\n",
	p_tuning->area_1000_txdll);
	pr_err("\tRX_DLL :: 0x%x\n",
	p_tuning->area_1000_rxdll);

	pr_err("---[100M]---\n");
	pr_err("\tTX_POL :: %s\n",
	((p_tuning->area_pol >> 1) & 1) == DLL_POL_FWD ? "FWD" : "REV");
	pr_err("\tRX_POL :: %s\n",
	((p_tuning->area_pol) & 1) == DLL_POL_FWD ? "FWD" : "REV");
	pr_err("\tTX_DLL :: 0x%x\n",
	p_tuning->area_100_txdll);
	pr_err("\tRX_DLL :: 0x%x\n",
	p_tuning->area_100_rxdll);
}

static void fh_external_phy_link_up_cb(void *pri)
{
	struct mii_bus *p_mii_bus;
	struct phy_device *phydev;
	struct phy_reg_cfg *p_reg_cfg;
	int i;

	struct soc_reg_tuning tuning_val = {0};
	unsigned int id = 0;

	p_mii_bus = (struct mii_bus *)pri;
	phydev = mdiobus_get_phy(p_mii_bus, 0);
	if (!phydev)
		return;

	memcpy(&tuning_val, g_tuning_buf, sizeof(struct soc_reg_tuning));
	//dump_pol_dll_info(&tuning_val);
	id = tuning_val.id_l | tuning_val.id_m << 8 | tuning_val.id_h << 16;
	for (i = 0, p_reg_cfg = phy_config_array;
	i < ARRAY_SIZE(phy_config_array); i++, p_reg_cfg++) {
		if (phydev->phy_id == p_reg_cfg->id) {
			if (id == (phydev->phy_id & DLL_ID_MASK)) {
				p_reg_cfg->tx_1000_polarity =
				(tuning_val.area_pol >> 3) & 1;
				p_reg_cfg->rx_1000_polarity =
				(tuning_val.area_pol >> 2) & 1;
				p_reg_cfg->tx_1000_dll_val =
				tuning_val.area_1000_txdll;
				p_reg_cfg->rx_1000_dll_val =
				tuning_val.area_1000_rxdll;
				p_reg_cfg->tx_100_polarity =
				(tuning_val.area_pol >> 1) & 1;
				p_reg_cfg->rx_100_polarity =
				(tuning_val.area_pol) & 1;
				p_reg_cfg->tx_100_dll_val =
				tuning_val.area_100_txdll;
				p_reg_cfg->rx_100_dll_val =
				tuning_val.area_100_rxdll;
				p_reg_cfg->tx_10_polarity =
				p_reg_cfg->tx_100_polarity;
				p_reg_cfg->rx_10_polarity =
				p_reg_cfg->rx_100_polarity;
				p_reg_cfg->tx_10_dll_val =
				p_reg_cfg->tx_100_dll_val;
				p_reg_cfg->rx_10_dll_val =
				p_reg_cfg->rx_100_dll_val;
			}
			if (p_reg_cfg->dll_enable == DLL_SETTING_ENABLE) {
				if (phydev->speed == SPEED_10) {
					fh_qos_set_phy_polarity(
					p_reg_cfg->tx_10_polarity,
					p_reg_cfg->rx_10_polarity);
					fh_qos_set_phy_dll_val(
					p_reg_cfg->tx_10_dll_val,
					p_reg_cfg->rx_10_dll_val);
				}

				else if (phydev->speed == SPEED_100) {
					fh_qos_set_phy_polarity(
					p_reg_cfg->tx_100_polarity,
					p_reg_cfg->rx_100_polarity);
					fh_qos_set_phy_dll_val(
					p_reg_cfg->tx_100_dll_val,
					p_reg_cfg->rx_100_dll_val);
				}

				else if (phydev->speed == SPEED_1000) {
					fh_qos_set_phy_polarity(
					p_reg_cfg->tx_1000_polarity,
					p_reg_cfg->rx_1000_polarity);
					fh_qos_set_phy_dll_val(
					p_reg_cfg->tx_1000_dll_val,
					p_reg_cfg->rx_1000_dll_val);
				}

			} else {
				if (phydev->speed == SPEED_1000)
					pr_err("Warning :: you may need to scan 1000M pll ....\n");
			}
			/*break match id..*/
			break;
		}
	}

}


static void fh_external_phy_link_down_cb(void *pri)
{

}

enum {
	CP_VAL_0,
	CP_VAL_1,
	VAL_100M_0,
	VAL_100M_1,
	VAL_10M_0,
	VAL_10M_1,
	TRAIN_MAX_SIZE,
};

static u32 train_100_array[] = {
	31, 30, 29, 28,
	27, 26, 25, 24,
	23, 22, 21, 20,
	19, 18, 17, 16,
	0,  1,  2,  3,
	4,  5,  6,  7,
	8,  9,  10, 11,
	12, 13, 14, 15,
};

static u32 train_10_array[] = {
	31, 30, 29, 28,
	27, 26, 25, 24,
	23, 22, 21, 20,
	19, 18, 17, 16,
	0,  1,  2,  3,
	4,  5,  6,  7,
	8,  9,  10, 11,
	12, 13, 14, 15,
};

static u32 train_cp_array[] = {
	0, 1, 2, 3,
};
#define REFIX_CP_TRAIN_DATA_OFFSET	    (0)
#define REFIX_100M_TRAIN_DATA_OFFSET    (0)
#define REFIX_10M_TRAIN_DATA_OFFSET	    (0)

struct s_train_val train_array[TRAIN_MAX_SIZE] = {

		[CP_VAL_0].name = "cp_val_0",
		[CP_VAL_0].src_add = REG_PMU_EPHY_PARAM,
		[CP_VAL_0].src_mask = 0xc0,
		[CP_VAL_0].src_vaild_index = 15,
		[CP_VAL_0].dst_add = 0x18,
		[CP_VAL_0].dst_vaild_index = 22,
		[CP_VAL_0].bind_train_array = train_cp_array,
		[CP_VAL_0].bind_train_size = ARRAY_SIZE(train_cp_array),
		[CP_VAL_0].usr_train_offset =
		REFIX_CP_TRAIN_DATA_OFFSET,

		[CP_VAL_1].name = "cp_val_1",
		[CP_VAL_1].src_add = REG_PMU_EPHY_PARAM,
		[CP_VAL_1].src_mask = 0xc0,
		[CP_VAL_1].src_vaild_index = 15,
		[CP_VAL_1].dst_add = 0xb7c,
		[CP_VAL_1].dst_vaild_index = 6,
		[CP_VAL_1].bind_train_array = train_cp_array,
		[CP_VAL_1].bind_train_size = ARRAY_SIZE(train_cp_array),
		[CP_VAL_1].usr_train_offset =
		REFIX_CP_TRAIN_DATA_OFFSET,

		[VAL_100M_0].name = "val_100M_0",
		[VAL_100M_0].src_add = REG_PMU_EPHY_PARAM,
		[VAL_100M_0].src_mask = 0x1f,
		[VAL_100M_0].src_vaild_index = 5,
		[VAL_100M_0].dst_add = 0x24,
		[VAL_100M_0].dst_vaild_index = 8,
		[VAL_100M_0].bind_train_array = train_100_array,
		[VAL_100M_0].bind_train_size = ARRAY_SIZE(train_100_array),
		[VAL_100M_0].usr_train_offset =
		REFIX_100M_TRAIN_DATA_OFFSET,

		[VAL_100M_1].name = "val_100M_1",
		[VAL_100M_1].src_add = REG_PMU_EPHY_PARAM,
		[VAL_100M_1].src_mask = 0x1f,
		[VAL_100M_1].src_vaild_index = 5,
		[VAL_100M_1].dst_add = 0x1308,
		[VAL_100M_1].dst_vaild_index = 8,
		[VAL_100M_1].bind_train_array = train_100_array,
		[VAL_100M_1].bind_train_size = ARRAY_SIZE(train_100_array),
		[VAL_100M_1].usr_train_offset =
		REFIX_100M_TRAIN_DATA_OFFSET,

		[VAL_10M_0].name = "val_10M_0",
		[VAL_10M_0].src_add = REG_PMU_EPHY_PARAM,
		[VAL_10M_0].src_mask = 0x1f00,
		[VAL_10M_0].src_vaild_index = 13,
		[VAL_10M_0].dst_add = 0x24,
		[VAL_10M_0].dst_vaild_index = 16,
		[VAL_10M_0].bind_train_array = train_10_array,
		[VAL_10M_0].bind_train_size = ARRAY_SIZE(train_10_array),
		[VAL_10M_0].usr_train_offset =
		REFIX_10M_TRAIN_DATA_OFFSET,

		[VAL_10M_1].name = "val_10M_1",
		[VAL_10M_1].src_add = REG_PMU_EPHY_PARAM,
		[VAL_10M_1].src_mask = 0x1f00,
		[VAL_10M_1].src_vaild_index = 13,
		[VAL_10M_1].dst_add = 0x1308,
		[VAL_10M_1].dst_vaild_index = 0,
		[VAL_10M_1].bind_train_array = train_10_array,
		[VAL_10M_1].bind_train_size = ARRAY_SIZE(train_10_array),
		[VAL_10M_1].usr_train_offset =
		REFIX_10M_TRAIN_DATA_OFFSET,
};

void dump_phy_train_val(struct s_train_val *p_train)
{
	pr_err("------------GAP_LINE---------------\n");
	pr_err("name            : %s\n", p_train->name);
	pr_err("src_add         : %08x\n", p_train->src_add);
	pr_err("src_mask        : %08x\n", p_train->src_mask);
	pr_err("src_vaild_index : %08x\n", p_train->src_vaild_index);
	pr_err("dst_add         : %08x\n", p_train->dst_add);
	pr_err("dst_vaild_index : %08x\n", p_train->dst_vaild_index);
	pr_err("usr_train_offset: %d\n", p_train->usr_train_offset);
}


void parse_train_data(struct s_train_val *p_train)
{

	unsigned long test_data;
	int i;
	u32 temp_data;
	u32 vaild_bit_pos;
	int max_offset, low_offset;
	u32 *array;
	u32 size;

	if (!va_ephy) {
		pr_err("ioremap internal phy err\n");
		BUG_ON(1);
	}

	array = p_train->bind_train_array;
	size = p_train->bind_train_size;
	test_data = p_train->src_mask;
	vaild_bit_pos = find_first_bit(&test_data, 32);

	if ((!array) ||
	((p_train->src_mask >> vaild_bit_pos) != (size - 1))) {
		pr_err("para error..\n");
		return;
	}

	temp_data = fh_pmu_get_reg(p_train->src_add);
	if (temp_data & (1 << p_train->src_vaild_index)) {
		/*got vaild val*/
		temp_data &= p_train->src_mask;
		temp_data >>= vaild_bit_pos;
		pr_err("[%s] :: train val %d\n", p_train->name, temp_data);
		/*find index*/
		for (i = 0; i < size; i++) {
			if (temp_data == array[i]) {
				max_offset = (size - 1) - i;
				low_offset = 0 - i;
				break;
			}
		}

		if ((p_train->usr_train_offset < low_offset) ||
		(p_train->usr_train_offset > max_offset)) {
			pr_err("offset [%d] should limit in [%d , %d]\n",
			p_train->usr_train_offset, low_offset, max_offset);
			return;
		}
		//fix array idx..
		i += p_train->usr_train_offset;
		temp_data = array[i];
		/*pr_err("fix idx :: [%d] = %d\n", i, temp_data);*/
	} else {
		temp_data = 0;
		pr_err("[%s] :: use default train data %d\n",
		p_train->name, temp_data);
	}
	temp_data &= (p_train->src_mask >> vaild_bit_pos);
	SET_REG_M((u32)va_ephy + p_train->dst_add,
	temp_data << p_train->dst_vaild_index,
	(p_train->src_mask >> vaild_bit_pos) << p_train->dst_vaild_index);

}

void fh_internal_phy_reset(void)
{
	int idx;

	pr_err("fh internal phy reset go...\n ");
	/*just map once*/
	if (!va_ephy)
		va_ephy = ioremap(EPHY_REG_BASE, SZ_16K);

	if (!va_ephy) {
		pr_err("ioremap internal phy err\n");
		BUG_ON(1);
	}

	fh_pmu_set_reg_m(REG_PMU_CLK_GATE1, 0, 1<<0);
	fh_pmu_set_reg_m(REG_PMU_SWRSTN_NSR, 0, 1<<23);
	fh_pmu_set_reg_m(REG_PMU_SWRST_APB_CTRL, 0, 1<<27);
	udelay(200);
	fh_pmu_set_reg_m(REG_PMU_SWRST_APB_CTRL, 1<<27, 1<<27);
	fh_pmu_set_reg_m(REG_PMU_SWRSTN_NSR, 1<<23, 1<<23);

	SET_REG((u32)va_ephy + 0x1370, 0x1006);
	SET_REG((u32)va_ephy + 0x0b84, 0x0600);
	SET_REG((u32)va_ephy + 0x1270, 0x1900);
	SET_REG((u32)va_ephy + 0x0b98, 0xd150);
	SET_REG((u32)va_ephy + 0x1274, 0x0000);
	SET_REG((u32)va_ephy + 0x0bf8, 0x0130);
	SET_REG((u32)va_ephy + 0x1374, 0x0009);
	SET_REG((u32)va_ephy + 0x0b6c, 0x0704);
	SET_REG((u32)va_ephy + 0x1340, 0x0000);
	SET_REG((u32)va_ephy + 0x0ba8, 0x0000);
	SET_REG((u32)va_ephy + 0x0b7c, 0x10c0);
	SET_REG((u32)va_ephy + 0x1308, 0x0000);
	SET_REG((u32)va_ephy + 0x1378, 0x1820);
	SET_REG((u32)va_ephy + 0x0000, 0x20000000);
	SET_REG((u32)va_ephy + 0x0004, 0x00000018);
	SET_REG((u32)va_ephy + 0x0014, 0x06000000);
	SET_REG((u32)va_ephy + 0x0018, 0x00c00040);
	SET_REG((u32)va_ephy + 0x001c, 0xa1800000);
	SET_REG((u32)va_ephy + 0x0020, 0x0002340c);
	//diff with ch2
	SET_REG((u32)va_ephy + 0x0024, 0x30000000);
	SET_REG((u32)va_ephy + 0x0028, 0x00402800);
	SET_REG((u32)va_ephy + 0x000c, 0xba0edfff);
	SET_REG((u32)va_ephy + 0x0010, 0x7fcbf9de);
	SET_REG((u32)va_ephy + 0x1224, 0x0000);
	SET_REG((u32)va_ephy + 0x12f0, 0x0000);
	SET_REG((u32)va_ephy + 0x0bc0, 0x07de);
	SET_REG((u32)va_ephy + 0x0bc8, 0x09de);
	SET_REG((u32)va_ephy + 0x070c, 0x0401);
	SET_REG((u32)va_ephy + 0x06b4, 0xfd00);
	SET_REG((u32)va_ephy + 0x0a84, 0x1d20);
	SET_REG((u32)va_ephy + 0x06d4, 0x3130);
	SET_REG((u32)va_ephy + 0x0a6c, 0x0818);
	SET_REG((u32)va_ephy + 0x0aec, 0x1000);
	SET_REG((u32)va_ephy + 0x0658, 0x1c00);
	SET_REG((u32)va_ephy + 0x07d4, 0x6900);
	SET_REG((u32)va_ephy + 0x06b8, 0x0004);
	SET_REG((u32)va_ephy + 0x06e4, 0x04a0);
	SET_REG((u32)va_ephy + 0x0bbc, 0x1759);
	SET_REG((u32)va_ephy + 0x0788, 0x000f);
	SET_REG((u32)va_ephy + 0x0680, 0x0552);
	SET_REG((u32)va_ephy + 0x06c8, 0xc000);
	SET_REG((u32)va_ephy + 0x06e0, 0x8508);
	SET_REG((u32)va_ephy + 0x1360, 0xff37);
	SET_REG((u32)va_ephy + 0x076c, 0x0430);
	SET_REG((u32)va_ephy + 0x0794, 0x9000);
	//led
	SET_REG((u32)va_ephy + 0x2c, 0x13);
	SET_REG_M((u32)va_ephy + 0x07f8, 3 << 8, 3 << 8);

	for (idx = 0; idx < ARRAY_SIZE(train_array); idx++) {
		/*dump_phy_train_val(&train_array[idx]);*/
		parse_train_data(&train_array[idx]);
	}
}

static void fh_internal_phy_link_up_cb(void *pri)
{

	if (!va_ephy) {
		pr_err("ioremap internal phy err\n");
		BUG_ON(1);
	}

	SET_REG((u32)va_ephy + 0x0b10, 0x5000);
	SET_REG((u32)va_ephy + 0x0b14, 0x8000);
	SET_REG((u32)va_ephy + 0x0b1c, 0x000e);
	SET_REG((u32)va_ephy + 0x0b20, 0x0004);
	SET_REG((u32)va_ephy + 0x0aec, 0x1800);
	SET_REG((u32)va_ephy + 0x0b10, 0x0000);
	SET_REG((u32)va_ephy + 0x0b14, 0x0000);

}

static void fh_internal_phy_link_down_cb(void *pri)
{

	if (!va_ephy) {
		pr_err("ioremap internal phy err\n");
		BUG_ON(1);
	}
	SET_REG((u32)va_ephy + 0xb10, 0x5000);
	SET_REG((u32)va_ephy + 0xb14, 0x8000);
	SET_REG((u32)va_ephy + 0xb1c, 0x000e);
	SET_REG((u32)va_ephy + 0xb20, 0x000e);
	SET_REG((u32)va_ephy + 0xb1c, 0x000f);
	SET_REG((u32)va_ephy + 0xb20, 0x0035);
	SET_REG((u32)va_ephy + 0xb1c, 0x0000);
	SET_REG((u32)va_ephy + 0xb10, 0x0000);
	SET_REG((u32)va_ephy + 0xb14, 0x0000);

}


static struct fh_gmac_platform_data fh_gmac_data = {

	.phy_sel = phy_sel_func,
	.inf_set = phy_inf_set,
	.gmac_reset = 0,
	.p_cfg_array = phy_config_array,
	.phy_info[0] = {
		.phy_sel = EXTERNAL_PHY,
		.phy_inf = PHY_INTERFACE_MODE_RGMII,
		.phy_reset = fh_external_phy_reset,
		.ex_sync_mac_spd = eth_set_speed,
		.brd_link_up_cb = fh_external_phy_link_up_cb,
		.brd_link_down_cb = fh_external_phy_link_down_cb,
	},

	.phy_info[1] = {
		.phy_sel = INTERNAL_PHY,
		.phy_inf = PHY_INTERFACE_MODE_MII,
		.phy_reset = fh_internal_phy_reset,
		.ex_sync_mac_spd = 0,
		.brd_link_up_cb = fh_internal_phy_link_up_cb,
		.brd_link_down_cb = fh_internal_phy_link_down_cb,
	},

};


struct fh_gmac_platform_data *fh_qos_parse_dts_node(struct platform_device *pdev){

	struct device_node *np = pdev->dev.of_node;
	struct fh_gmac_platform_data *ret_plat;
	u32 temp;
	pr_err("fh_gmac_parse_dts_node get in....\n");

	ret_plat = &fh_gmac_data;
	if (!of_property_read_u32(np, "phyreset-gpio", &temp)) {
		ret_plat->phy_reset_pin = temp;
		g_external_reset_pin = temp;
	}
	if (!of_property_read_u32(np, "soc-tuning-l", &temp)) {
		g_tuning_buf[0] =
		fh_pmu_get_reg(SYS_REG_P2V(CPU_CTRL_REG_BASE) + temp);
	}

	if (!of_property_read_u32(np, "soc-tuning-h", &temp)) {
		g_tuning_buf[1] =
		fh_pmu_get_reg(SYS_REG_P2V(CPU_CTRL_REG_BASE) + temp);
	}
	pr_err("ret_plat->phy_reset_pin is %x\n",ret_plat->phy_reset_pin);
	return ret_plat;

}
